package com.uuah.server.transport.service;

import java.util.Collection;
import java.util.Iterator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uuah.server.UuahServer;
import com.uuah.server.api.IUuahContext;
import com.uuah.server.api.endpoint.IEndpointURI;
import com.uuah.server.api.endpoint.IUuahEndpoint;
import com.uuah.server.api.transport.IConnector;
import com.uuah.server.api.transport.service.ITransportServiceDescriptor;
import com.uuah.server.config.i18n.ServerMessages;
import com.uuah.server.config.registry.ServiceDescriptorFactory;
import com.uuah.server.exception.registry.ServiceException;
import com.uuah.server.exception.transport.service.TransportFactoryException;
import com.uuah.server.transport.AbstractConnector;
import com.uuah.server.util.UuahServerUtils;
import com.uuah.utils.BeanUtils;

/**
 *<code>TransportFactory</code> can be used for generically creating endpoints
 * from an url. Note that for some endpoints, the url alone is not enough to
 * create the endpoint if a connector for the endpoint has not already been
 * configured with the Uuah Manager.
 *
 * <p>
 * update record:updator，update time，update content and version
 * </p>
 *
 * @author <a href="jonny_quan@hotmail.com">jonny</a>
 * @date 2009 2009-3-27 下午02:48:40
 * @version 1.0.0
 */
public class TransportFactory {
	protected transient final Logger logger = LoggerFactory
			.getLogger(TransportFactory.class);

	public static IConnector createConnector(IEndpointURI url,
			IUuahContext uuahContext) throws TransportFactoryException {

		try {
			IConnector connector;
			String scheme = url.getSchemeMetaInfo();

			ITransportServiceDescriptor sd = (ITransportServiceDescriptor) UuahServer
					.getUuahContext().getRegistry().lookupServiceDescriptor(
							ServiceDescriptorFactory.PROVIDER_SERVICE_TYPE,
							scheme);
			if (sd == null) {
				throw new ServiceException(ServerMessages
						.noServiceTransportDescriptor(scheme));
			}

			connector = sd.createConnector();
			if (connector != null) {
				if (connector instanceof AbstractConnector) {
					((AbstractConnector) connector).initialiseFromUrl(url);
				}
			} else {
				throw new TransportFactoryException(ServerMessages
						.objectNotSetInService("Connector", scheme));
			}

			connector.setName(UuahServerUtils.getConnectorName(connector));

			return connector;
		} catch (Exception e) {
			throw new TransportFactoryException(ServerMessages
					.failedToCreateObjectWith("Endpoint", url), e);
		}
	}

	public static IConnector getOrCreateConnectorByProtocol(
			IUuahEndpoint endpoint, IUuahContext uuahContext)
			throws TransportFactoryException {
		return getOrCreateConnectorByProtocol(endpoint.getEndpointURI(),
				uuahContext);
	}

	public static IConnector getOrCreateConnectorByProtocol(IEndpointURI uri,
			IUuahContext uuahContext) throws TransportFactoryException {
		String connectorName = uri.getConnectorName();
		if (null != connectorName) {
			IConnector connector = UuahServer.getUuahContext().getRegistry()
					.lookupConnector(connectorName);
			if (connector != null) {
				return connector;
			}
		}

		IConnector connector = getConnectorByProtocol(uri.getFullScheme());
		if (connector == null) {
			connector = createConnector(uri, uuahContext);
			try {
				BeanUtils.populate(connector, uri.getParams());
				connector.setUuahContext(uuahContext);
				uuahContext.getRegistry().registerConnector(connector);
			} catch (Exception e) {
				throw new TransportFactoryException(e);
			}
		}
		return connector;
	}

	public static IConnector getConnectorByProtocol(String protocol) {
		IConnector connector;
		IConnector resultConnector = null;
		Collection connectors = UuahServer.getUuahContext().getRegistry()
				.lookupObjects(IConnector.class);
		for (Iterator iterator = connectors.iterator(); iterator.hasNext();) {
			connector = (IConnector) iterator.next();
			if (connector.supportsProtocol(protocol)) {
				if (resultConnector == null) {
					resultConnector = connector;
				} else {
					throw new IllegalStateException(ServerMessages
							.moreThanOneConnectorWithProtocol(protocol)
							.getMessage());
				}
			}
		}
		return resultConnector;
	}
}
